'use strict'

import utils from 'axios/unsafe/utils.js'

/**
 * Create an Error with the specified message, config, error code, request and response.
 *
 * @param {string} message The error message.
 * @param {string} [code] The error code (for example, 'ECONNABORTED').
 * @param {Object} [config] The config.
 * @param {Object} [request] The request.
 * @param {Object} [response] The response.
 *
 * @returns {Error} The created error.
 */
function AxiosError(message, code, config, request, response) {
	Error.call(this)

	if (Error.captureStackTrace) {
		Error.captureStackTrace(this, this.constructor)
	} else {
		this.stack = new Error().stack
	}

	this.message = message
	this.name = 'AxiosError'
	code && (this.code = code)
	config && (this.config = config)
	request && (this.request = request)
	if (response) {
		this.response = response
		this.status = response.status ? response.status : null
	}
}

utils.inherits(AxiosError, Error, {
	toJSON: function toJSON() {
		return {
			// Standard
			message: this.message,
			name: this.name,
			// Microsoft
			description: this.description,
			number: this.number,
			// Mozilla
			fileName: this.fileName,
			lineNumber: this.lineNumber,
			columnNumber: this.columnNumber,
			stack: this.stack,
			// Axios
			config: utils.toJSONObject(this.config),
			code: this.code,
			status: this.status
		}
	}
})

const prototype = AxiosError.prototype
const descriptors = {}

;[
	'ERR_BAD_OPTION_VALUE',
	'ERR_BAD_OPTION',
	'ECONNABORTED',
	'ETIMEDOUT',
	'ERR_NETWORK',
	'ERR_FR_TOO_MANY_REDIRECTS',
	'ERR_DEPRECATED',
	'ERR_BAD_RESPONSE',
	'ERR_BAD_REQUEST',
	'ERR_CANCELED',
	'ERR_NOT_SUPPORT',
	'ERR_INVALID_URL'
].forEach(code => {
	descriptors[code] = { value: code }
})

Object.defineProperties(AxiosError, descriptors)
Object.defineProperty(prototype, 'isAxiosError', { value: true })

AxiosError.from = (error, code, config, request, response, customProps) => {
	const axiosError = Object.create(prototype)

	utils.toFlatObject(
		error,
		axiosError,
		function filter(obj) {
			return obj !== Error.prototype
		},
		prop => {
			return prop !== 'isAxiosError'
		}
	)

	AxiosError.call(axiosError, error.message, code, config, request, response)

	axiosError.cause = error

	axiosError.name = error.name

	customProps && Object.assign(axiosError, customProps)

	return axiosError
}

export default AxiosError
